import ast
import asyncio
import logging
from threading import Thread
import websockets
import time
import json
from analyse import RTPeakAndDatasAnalyser
from virtualDataClient import virtualDataClient

# webserver 通用
class Server:
    def __init__(self, port, onDataCallback = None):
        self.clients = {}
        self.onDataCallback = onDataCallback
        self.port = port

    def start(self):
        asyncio.run(self.main())

    async def handle(self, websocket, path):
        print(path)
        self.clients[path] = websocket
        try:
            if path == '/data':
                async for message in websocket:  # 实例msg  {"personId": 0, "channel": [1, 1, 1, 1, 1, 1, 1]}
                    # print ('msg:', message)
                    if self.onDataCallback != None:
                        await self.onDataCallback(message)

            elif path == '/unity':
                async for message in websocket:
                    print(message)
                    # 因为无需接收数据，所以pass，保证连接不断就行
                    await websocket.send(message)

            else:
                print('wrong path')

        except websockets.ConnectionClosed:
            print(path, 'connection closed')

    async def main(self):
        async with websockets.serve(self.handle, "0.0.0.0", self.port):
            await asyncio.Future()  # run forever
    
    async def sendMsgToUnity(self, msg):
        if (self.clients.get('/unity') == None):
            print('unity is not connected')
            return
        await self.clients['/unity'].send(msg)
    

# 作为客户端连接unity
class Connector:
    def __init__(self, url):
        self.ws = None
        self.url = url
    
    # 开个线程连接unity
    def connect(self):
        print('connecting : ', self.url, '......')
        thread = Thread(target=lambda: asyncio.run(self._connect()))
        thread.start()
        while self.ws == None:
            pass
        print('connect', self.url, 'success')

    async def sendMsg(self, msg):
        print("Connector::sendMsg, arg", msg)
        await self.ws.send(msg)

    async def _connect(self):
        self.ws = await websockets.connect(self.url)
        await asyncio.Future()


# 封装发送给unity端的数据
class Sender:
    def __init__(self, connector):
        self.connector = connector
    
    # [波峰出现时刻, 人id, 第几个通道(从0开始)]
    async def sendPeakTimeToUnity(self, data):
        # await self.connector.sendMsg(json.dumps({'type': 'peakTime', 'data': data}))
        await self.connector.sendMsg(json.dumps({'type': 'peakTime', 'time': data[0], 'personId': data[1], 'channelId': data[2]}))
    # [时刻，人id，频率]
    async def sendFrequenceToUnity(self, data):
        # await self.connector.sendMsg(json.dumps({'type': 'frequence', 'data': data}))
        await self.connector.sendMsg(json.dumps({'type': 'frequence', 'time': data[0], 'personId': data[1], 'frequence': data[2]}))

    # 发送相对划桨
    # [时刻，人id，相对划距]
    async def sendOarDistanceToUnity(self, data):
        # await self.connector.sendMsg(json.dumps({'type': 'oarDistance', 'data': data}))
        await self.connector.sendMsg(json.dumps({'type': 'oarDistance', 'time': data[0], 'personId': data[1], 'distance': data[2]}))

    # 发送划桨和收桨的时间比
    # [时刻，人id，比]
    async def sendGoAndBackToUnity(self, data):
        # await self.connector.sendMsg(json.dumps({'type': 'goAndBack', 'data': data}))
        await self.connector.sendMsg(json.dumps({'type': 'goAndBack', 'time': data[0], 'personId': data[1], 'ratio': data[2]}))

    # 发送一致性
    # [时刻，一致性]
    async def sendConsistencyToUnity(self, data):
        # await self.connector.sendMsg(json.dumps({'type': 'consistency', 'data': data}))
        await self.connector.sendMsg(json.dumps({'type': 'consistency', 'time': data[0], 'personId': data[1], 'consistency': data[2]}))
    

# 龙舟webserver 服务器，带业务了
class DragonBoatServer:
    # personNum 客户端发来几个人的数据
    # port      服务器端口
    # uintyUrl  unity端webserver链接
    def __init__(self, personNum, port, unityUrl):
        self.connector = Connector(url=unityUrl)
        self.server = Server(port= port, onDataCallback=self.onData)
        self.sender = Sender(self.connector)
        
        self.personNum = personNum
        self.analysers = [RTPeakAndDatasAnalyser(self.sender) for i in range(personNum)]

    # 启动服务器
    def start(self):
        self.connector.connect()
        self.server.start()
    
    # 接收数据端发来的一个数据包data时调用此函数
    async def onData(self, message):
        # print("DragonBoatServer::onData, arg", data)
        data = json.loads(message)  # data 格式示例  data = {'personId': 0, 'channel' :[1,1,1,1,1,1,1,1]}
        personId = data['personId']
        channel = data['channel']
        await self.analysers[personId].analyse(channel)
        # await self.sender.sendPeakTimeToUnity('hello')


if __name__ == '__main__':
    # ws://localhost:8765/data
    # ws://localhost:8765/unity
    # ws://218.106.117.240:8765/unity
    server = DragonBoatServer(4, port = 8765, unityUrl="ws://biglun.xyz:12345/echo")
    
    serverThread = Thread(target=server.start)
    dataThread = Thread(target=lambda: asyncio.run(virtualDataClient()))
    serverThread.start()
    dataThread.start()